/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						 combat_path_finder_base.h

	$Header: /heroes4/combat_path_finder_base.h $

	$NoKeywords: $

 ************************************************************************/

#if !defined( COMBAT_PATH_FINDER_BASE_H_INCLUDED )
#define COMBAT_PATH_FINDER_BASE_H_INCLUDED

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <queue>
#include "combat_path.h"
#include "isometric_map.h"

class t_combat_object_base;
class t_battlefield;
class t_combat_footprint;

// ---------------------------------------------------------------
// class to find paths for adventure map
// ---------------------------------------------------------------

// ---------------------------------------------------------------
// structure marking state of individual cells - blocked, in tower footprint, has
// castle wall
// ---------------------------------------------------------------
struct t_combat_path_blockage
{
	unsigned blocked	: 1;
	unsigned forbidden	: 1;
	unsigned in_tower	: 1;
	unsigned has_wall	: 1;
};

// ---------------------------------------------------------------
// map of blockage information 
// ---------------------------------------------------------------
class t_combat_path_blockage_map : public t_isometric_map<t_combat_path_blockage>
{
public:
	t_combat_path_blockage_map( int size, int tile_height, t_screen_point const& view_size,
								t_combat_path_blockage const&	value );

	t_combat_path_blockage can_place( t_map_point_2d const& point,
		                              t_combat_footprint const& footprint ) const;
	void				   mark( t_map_point_2d const&		point,
		                         t_combat_footprint const&	footprint,
								 t_combat_path_blockage		value );
	void				   mark_obstacles( t_battlefield& battlefield );
};

inline 
t_combat_path_blockage_map::t_combat_path_blockage_map( int size, int			tile_height,
													    t_screen_point const&	view_size,
														t_combat_path_blockage const& value  )
						  : t_isometric_map<t_combat_path_blockage>( size, tile_height,
						                                             view_size, value )
{
}

// ---------------------------------------------------------------
// map of path data, movement costs, and passability for a given footprint size
// ---------------------------------------------------------------
class t_combat_path_map : public t_isometric_map<t_combat_path_data>
{
public:
	t_combat_path_map( int size );

	int  get_footprint_size() const;
	void init_map( t_battlefield const& battlefield, t_combat_path_blockage_map const& map, 
		           t_combat_footprint const& footprint );
	void mark_obstacle( t_combat_object_base const& object,
		                t_combat_path_blockage const& state );
protected:
	int m_footprint_size;
};

inline int t_combat_path_map::get_footprint_size() const
{
	return m_footprint_size;
}

// ---------------------------------------------------------------
// priority queue for path finder
// ---------------------------------------------------------------
class t_combat_path_queue : public std::priority_queue< t_combat_path_point,
														std::vector<t_combat_path_point>, 
														std::greater< t_combat_path_point > >
{
public:
	void clear();
};

inline void t_combat_path_queue::clear()
{
	c.clear();
}

// ---------------------------------------------------------------
// class to find paths for adventure map
// ---------------------------------------------------------------
class t_combat_path_finder_base
{
public:
	explicit t_combat_path_finder_base( int size );

	void					  clear();
	t_combat_path_data const& get_data( t_map_point_2d const& point );
	bool                      get_path( t_map_point_2d destination, t_combat_path& path );
	int						  get_row_end( int row ) const;
	int						  get_row_start( int row ) const;
	int						  get_size() const;
protected:
	void		 clear_map( t_battlefield const&				battlefield,
							t_combat_path_blockage_map const&	map,
		                    t_combat_footprint const&			footprint  );
	virtual void generate_paths() = 0;
	void		 push( t_combat_path_point const& point );
	void		 push_first_point( t_map_point_2d const& cell );
	void		 mark_reachable_points( t_combat_footprint const& footprint );

	bool				m_initialized;
	t_combat_path_queue	m_open_points;
	t_combat_path_map	m_data;
};

inline void t_combat_path_finder_base::clear()
{
	m_initialized = false;
}


inline t_combat_path_data const& t_combat_path_finder_base::get_data( t_map_point_2d const& point )
{
	generate_paths();
	return m_data.get( point );
}

inline int t_combat_path_finder_base::get_row_end( int row ) const
{
	return m_data.get_row_end( row );
}

inline int t_combat_path_finder_base::get_row_start( int row ) const
{
	return m_data.get_row_start( row );
}

inline int t_combat_path_finder_base::get_size() const
{
	return m_data.get_size();
}

inline void t_combat_path_finder_base::clear_map( t_battlefield const&			    battlefield,
												  t_combat_path_blockage_map const& map, 
												  t_combat_footprint const&		    footprint  )
{
	m_data.init_map( battlefield, map, footprint );
}


#endif // COMBAT_PATH_FINDER_BASE_H_INCLUDED